package com.web_bloks.jsonp.client;

import com.web_bloks.system.client.Logger;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * Creates a 'callback wrapper' in the current window context.
 * This wrapper in turn will call the desired callback in
 * the GWT context.
 * 
 * Usage:
 * 1) derive e.g. JSONPcallback
 * 2) instantiate
 * 3) set callback target
 * 4) create()
 * 5) getCallbackName()  (to configure the URL of the script i.e. callback=)
 * 6) _clean()
 * 
 * @author Jean-Lou Dupont
 *
 */
public class BaseCallback {

	/**
	 * Instance Counter
	 */
	static int instanceCounter = 0;
	
	/**
	 * Callback fired status
	 */
	boolean callbackFired = false;

	/**
	 * Target for the callback
	 */
	BaseCallbackEvent target=null;
	
	/**
	 * Current callback id
	 */
	int currentCallback = -1;
	
	/*===================================================================
	 * CONSTRUCTORS
	 ===================================================================*/
	public BaseCallback() {
		super();
		setup();
	}
	private void setup() {
		_clean();
	}
	/*===================================================================
	 * PUBLIC
	 ===================================================================*/
	/**
	 * Creates a new callback
	 * CAUTION: do call until it is safe to delete the previous callback
	 */
	public void create() {

		if ( this.target == null ) {
			throw new RuntimeException( getClass() + ".create: target is null" );
		}
		
		if (this.currentCallback > 0) {
			deleteCallback( this.currentCallback );
		}
		
		this.callbackFired = false;
		this.currentCallback = instanceCounter++;
		Logger.log(getClass()+".create: creating callback name["+getCallbackName()+"]");
		this.createCallback( this.currentCallback );
	}
	/**
	 * 
	 * @param target
	 */
	public void setTarget(BaseCallbackEvent target) {
		this.target = target;
	}
	/**
	 * 
	 * @return String
	 */
	public String getCallbackName() {
		return "BaseCallbackFnc"+String.valueOf(this.currentCallback)+".handler";
	}
	/*===================================================================
	 * CALLBACK
	 ===================================================================*/
	/**
	 * Method called by the callback-wrapper. This is done through
	 * the calling script's 'callback' support.  
	 */
	public void callback(int id, JavaScriptObject obj) {
		
		this.callbackFired = true;
		Logger.log(getClass()+": callback called! id["+id+"]");
		
		// fire-off the event
		this.target.handleCallbackEvent(id, obj);
	}
	/**
	 * BLACK MAGIC at work!!!
	 *  this$static is a parameter passed to this method as the "this" pointer
	 *  of the current object. Hopefully, this won't change in future versions...
	 *  I had to look at the generated "detailed" code to figure this one out.
	 */
	protected native void createCallback(int id) /*-{

		var fncName = "BaseCallbackFnc"+id;
		eval( "var obj = $wnd."+fncName+" = { id: '" + id + "' };"	);
		obj.handler = function(jsObj) {
			this$static.@com.web_bloks.jsonp.client.BaseCallback::callback(ILcom/google/gwt/core/client/JavaScriptObject;)(this.id, jsObj);
		};
		
	}-*/;
	/**
	 * Deletes a callback
	 */
	protected native void deleteCallback(int id) /*-{
		var fncName = "BaseCallbackFnc"+id;	
		eval( "del $wnd."+fncName+";" );
		//eval( "$wnd."+fncName+" = null;" );
	}-*/;
	
	/*===================================================================
	 * ObjectPool
	 ===================================================================*/
	public void _clean() {
		
		if (this.currentCallback > 0) {
			deleteCallback( this.currentCallback );
		}
		this.currentCallback = -1;
		this.callbackFired = false;
		this.target = null;
	}

	
}//END